﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace PetGo
{
    /// <summary>
    /// represents the board
    /// </summary>
    partial class Board
    {
        public static int test = 0;

        public static int CenterOfDeadShapeMove = -1;
        public static int CenterOfDeadShapeMove_Killer = -1;

        public static Board sekiboard;

        public static Dictionary<int, int> moves = new Dictionary<int, int>();
        public static Dictionary<int, int> movesb = new Dictionary<int, int>();
        public static Dictionary<int, int> movesw = new Dictionary<int, int>();
        public static Dictionary<int, Group> thekilled = new Dictionary<int, Group>();

        static List<int> BAlive = new List<int>();
        static List<int> WAlive = new List<int>();

        static Dictionary<int, int> capturesave = new Dictionary<int, int>();
        static Dictionary<int, int> savemoves1 = new Dictionary<int, int>();
        static Dictionary<int, int> hanemoves = new Dictionary<int, int>();
        public static Dictionary<int, int> capturemoves1 = new Dictionary<int, int>();

        public Dictionary<int, List<int>> sekiLibs = new Dictionary<int, List<int>>();

        static int savemovescount=0;
        static int hanemovescount=0;
        static int capturemovescount=0;
        static public int randmovescount=0;
        static int noselfatarirandmovescount = 0;
        static int capturesavemovescount = 0;

        static List<int> theList = new List<int>();
        static int alsoChecked;
        public Dictionary<int, int> myGroupPosition;
        public Dictionary<int, Group> myGroup;
        public int myboardsize;
        public int myKoField;
        public Game myGame;
        public double myResult;
        public color myWinner;
        public color mytoMove;
        public List<int> mymovehistory;
        //public List<int> myEmptyFields;
        public Dictionary<int, int> myEmptyFields;
        static public Random myRandom = new Random();

        

        public Board(int boardsize, Game game)
        {
            

            myboardsize = boardsize;
            myGame = game;
            mymovehistory = new List<int>();
            myGroupPosition = new Dictionary<int, int>();
            myGroup = new Dictionary<int, Group>();
            myEmptyFields = new Dictionary<int, int>();
            // default is black playing first
            mytoMove = color.black;
        }
        public void fillEmptyFieldsList(Dictionary<int, int> theEmptys)
        {
            myEmptyFields = new Dictionary<int, int>(theEmptys);
            //for (int i = 0; i < myboardsize * myboardsize; ++i)
            //{
            //    if (!myGroupPosition.ContainsKey(i))
            //    {
            //        myEmptyFields.Add(i);
            //    }
            //}
        }
       

        public void fillEmptyFieldsList()
        {
            myEmptyFields.Clear();
            for (int i = 0; i < myboardsize * myboardsize; ++i)
            {
                if (!myGroupPosition.ContainsKey(i))
                {
                    myEmptyFields[i] = i;
                }
            }
        }
        /// <summary>
        /// places a stone on the position of the color
        /// </summary>
        /// <param name="thepos">position</param>
        /// <param name="thecolor">color of placement</param>
        public void place(int thepos, color thecolor)
        {
           
            int theko = -1;
            Group groupfound = null;
            thekilled.Clear();
            CenterOfDeadShapeMove = -1;
            foreach (int cGroup in Group.getNeighbors(thepos, myboardsize).Keys)
            {
                // is there a group
                if (myGroupPosition.ContainsKey(cGroup))
                {
                    if (myGroup[myGroupPosition[cGroup]].myColor == thecolor)
                    {
                        if (groupfound == null)
                        {
                            // new field for existing group:
                            groupfound = myGroup[myGroupPosition[cGroup]];
                            //myGroup[myGroupPosition[cGroup]].addField(thepos, this);
                        }
                        else
                        {
                            //groupfound.merge(myGroup[myGroupPosition[cGroup]], this);
                            if (groupfound.myposition != myGroup[myGroupPosition[cGroup]].myposition)
                            {
                                // merges into the group groupfound
                                // use smaller group to merge
                                if (myGroup[myGroupPosition[cGroup]].myFields.Count > groupfound.myFields.Count)
                                {
                                    myGroup[myGroupPosition[cGroup]].merge(groupfound, this);
                                    groupfound = myGroup[myGroupPosition[cGroup]];
                                }
                                else
                                {
                                    groupfound.merge(myGroup[myGroupPosition[cGroup]], this);
                                }
                            }
                        }
                    }
                    else
                    {
                        if (myGroup[myGroupPosition[cGroup]].myLibs.ContainsKey(thepos))
                        {
                            myGroup[myGroupPosition[cGroup]].myLibs.Remove(thepos);
                            myGroup[myGroupPosition[cGroup]].mypotEye.Remove(thepos);
                            
                        }
                        //--myGroup[myGroupPosition[cGroup]].mylibs;
                        // if this was last liberty of opponents group dispose the group
                        //int liberties = 0;
                        //foreach (int i in myGroup[myGroupPosition[cGroup]].myNeighbors.Keys)
                        //{
                        //    if (!myGroupPosition.ContainsKey(i) && i != thepos)
                        //    {
                        //        liberties++;
                        //        if (liberties > 0) break;
                        //    }
                        //}
                        if (myGroup[myGroupPosition[cGroup]].myLibs.Count == 0)
                        {
                            if (myGroup[myGroupPosition[cGroup]].myFields.Count == 1) theko = cGroup;
                            thekilled[myGroupPosition[cGroup]] = myGroup[myGroupPosition[cGroup]];
                        }
                    }
                }
                else
                {
                    // nada
                }
            }
            
            if (groupfound == null)
            {
                myGroupPosition[thepos] = thepos;
                groupfound = new Group(thepos, myboardsize, thecolor, this);
                myGroup[myGroupPosition[thepos]] = groupfound;
            }
            else
            {
                groupfound.addField(thepos, this, false);
                // if the placement belongs to existing group, no ko
                theko = -1;
            }

            if (thekilled.Count > 1)
            {
                // if more than one group is killed, no ko
                theko = -1;
            }

            else
            {
                if (thekilled.Count == 1)
                {
                    Group theKilledGroup = thekilled.ElementAt(0).Value;
                    if (theKilledGroup.myFields.Count > 2 && theKilledGroup.myFields.Count < 6)
                    {
                        CenterOfDeadShapeMove = getCenterOfDeadShapeMove(thekilled.ElementAt(0).Value.myFields.Keys.ToList());
                        checkDeadEyeShape(theKilledGroup.myFields.Keys.ToList());
                    }
                    if (theKilledGroup.myFields.Count == 2)
                    {
                        CenterOfDeadShapeMove = -2;
                        foreach(int g in theKilledGroup.myFields.Keys)
                        {
                            if (getx(g) > 0 && gety(g) > 0)
                            {
                                CenterOfDeadShapeMove = -1;
                                break;
                            }
                        }
                        if (CenterOfDeadShapeMove == -2)
                        {
                            foreach (int g in theKilledGroup.myFields.Keys)
                            {
                                foreach (int neiG in Group.getNeighbors_rad_no_cache(g, this, 1).Keys)
                                {
                                    if (myGroup[myGroupPosition[neiG]].myColor == theKilledGroup.myColor && !theKilledGroup.myFields.ContainsKey(neiG) && (myGroup[myGroupPosition[neiG]].myEyes.Count>1 || myGroup[myGroupPosition[neiG]].myLibs.Count > groupfound.myLibs.Count+1))
                                    {
                                        if (getdistance_int(g, neiG) < 3)
                                        {
                                            CenterOfDeadShapeMove = g;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    if (CenterOfDeadShapeMove > -1 && myEmptyFields.ContainsKey(CenterOfDeadShapeMove))
                    {
                        CenterOfDeadShapeMove_Killer = thepos;
                    }
                }
            }
            foreach (Group cKilled in thekilled.Values) cKilled.killed_new(this);

            myKoField = theko;
            mymovehistory.Add(thepos);
            groupfound.checkeyes_now(this);
            myEmptyFields.Remove(thepos);
            if (CenterOfDeadShapeMove_Killer > -1 && myGroup[myGroupPosition[CenterOfDeadShapeMove_Killer]].myEyes.Count > 0)
            {
                CenterOfDeadShapeMove_Killer = -1;
            }
            //if (groupfound.myEyes.ContainsKey(thepos))
            //{
            //    groupfound.myEyes.Remove(thepos);
            //}

            // Check
            //foreach (Group cGroup in myGroup.Values)
            //{
            //    if (cGroup.myLibs.Count != cGroup.getLibertyCount(this))
            //    {
            //        ;
            //    }
            //}
            //Checks
            //foreach (Group cGroup in myGroup.Values)
            //{
            //    foreach (int pos in cGroup.myEyes.Keys)
            //    {

            //        if (myGroupPosition.ContainsKey(pos))
            //        {
            //            if (myGroup[myGroupPosition[pos]].myColor == cGroup.myColor)
            //            {
            //                ;
            //            }
            //        }
            //    }
            //}
            //foreach(Group cGroup in myGroup.Values)
            //{
            //    foreach(int pos in cGroup.myFields.Keys)
            //    {
            //        foreach (int nei in Group.getNeighbors(pos, myboardsize).Keys)
            //        {
            //            if (cGroup.myFields.ContainsKey(nei)) continue;
            //            if (!cGroup.myNeighbors.ContainsKey(nei))
            //            {
            //                ;
            //            }
            //            if (!myGroupPosition.ContainsKey(nei) && !cGroup.myLibs.ContainsKey(nei))
            //            {
            //                ;
            //            }
            //        }
            //    }
            //}
            //foreach(int pos in myEmptyFields)
            //{
            //    if (myGroupPosition.ContainsKey(pos))
            //    {
            //        ;
            //    }
            //}
            //for (int i = 0; i < myboardsize * myboardsize; ++i)
            //{
            //    if (!myGroupPosition.ContainsKey(i))
            //    {
            //        if (!myEmptyFields.Contains(i))
            //        {
            //            ;
            //        }
            //    }
            //}
            //writeboardandwait();
            //if (mymovehistory.Count < 20)
            //{
            checkSeki(groupfound, true);
           
            //    foreach (int nei in groupfound.myNeighbors.Keys)
            //    {
            //        if (myGroupPosition.ContainsKey(nei))
            //        {
            //            checkSeki(myGroup[myGroupPosition[nei]]);
            //        }
            //    }
            //}
            checkBigEye(groupfound, thepos);
            //foreach(int e in myEmptyFields)
            //{
                
            //    if (ispotentialeye(e))
            //    {
            //        bool ef = false;
            //        foreach(Group g in myGroup.Values)
            //        {
            //            if (g.mypotEye.ContainsKey(e) || g.myEyes.ContainsKey(e))
            //            {
            //                ef = true;
            //                break;
            //            }
            //        }
            //        if (ef == false)
            //        {
            //            ;
            //        }
            //    }
            //}
        }

        private void checkDeadEyeShape(List<int> theKilledGroup)
        {
            if (theKilledGroup.Count > 3)
            {
                int dis = 0;
                foreach (int f in theKilledGroup)
                {
                    dis += getdistance_int(CenterOfDeadShapeMove, f);
                    //if (getdistance_int(CenterOfDeadShapeMove, f) > 2 || (getdistance_int(CenterOfDeadShapeMove, f) > 1 && theKilledGroup.myFields.Count == 4))
                    //{
                    //    if (getdistance_int(CenterOfDeadShapeMove, f) > 1 && theKilledGroup.myFields.Count == 4)
                    //    {
                    //        ;
                    //    }
                    //    CenterOfDeadShapeMove = -1;
                    //    break;
                    //}
                }
                switch (theKilledGroup.Count)
                {
                    case 4:
                        if (dis > 3)
                        {
                            CenterOfDeadShapeMove = -1;
                            if (dis != 6)
                            {
                                ;
                            }
                        }
                        break;
                    case 5:
                        if (dis > 5)
                        {
                            CenterOfDeadShapeMove = -1;
                        }
                        break;
                    default:
                        CenterOfDeadShapeMove = -1;
                        break;
                }
            }
        }

        private void checkBigEye(Group groupfound, int thepos)
        {
            if (CenterOfDeadShapeMove == -1)
            {
                if (groupfound.myFields.Count < 5) return;
                if (groupfound.myEyes.Count > 0) return;
                if (groupfound.myLibs.Count < 3) return;
                if (groupfound.myLibs.Count > 8) return;
                if (groupfound.mypotEye.Count > 0) return;
                //foreach (int lib in groupfound.myLibs.Keys)
                foreach (int lib in Group.getNeighbors(thepos, myboardsize).Keys)
                {
                    if (!myGroupPosition.ContainsKey(lib))
                    {
                        Group.eyes = new List<int>();
                        groupfound.getFieldsOfMyAliveGroups(lib, this, false);
                        if (Group.eyes != null && Group.eyes.Count > 2)
                        {
                            CenterOfDeadShapeMove = getCenterOfDeadShapeMove(Group.eyes);
                            checkDeadEyeShape(Group.eyes);

                        }
                    }
                    else
                    {
                        if (myGroup[myGroupPosition[lib]].myLibs.Count == 1 &&
                            myGroup[myGroupPosition[lib]].myColor != groupfound.myColor)
                        {
                            CenterOfDeadShapeMove = -1;
                            return;
                        }
                    }
                }
                
                foreach(int lib in groupfound.myNeighbors.Keys)
                {
                    if (myGroupPosition.ContainsKey(lib))
                    {
                        if (myGroup[myGroupPosition[lib]].myLibs.Count == 1)
                        {
                            CenterOfDeadShapeMove = -1;
                            return;
                        }
                    }
                }
                //if (CenterOfDeadShapeMove > 0)
                //{
                   
                //}
            }


            //if (CenterOfDeadShapeMove == -1)
            //{
            //    foreach (int lib in groupfound.myLibs.Keys)
            //    //foreach (int lib in Group.getNeighbors(thepos, myboardsize).Keys)
            //    {
            //        if (myGroupPosition.ContainsKey(lib)) continue;
            //        Group.eyes = new List<int>();
            //        groupfound.getFieldsOfMyAliveGroups(lib, this, false);
            //        if (Group.eyes != null && Group.eyes.Count > 2)
            //        {
            //            CenterOfDeadShapeMove = getCenterOfDeadShapeMove(Group.eyes);
            //            checkDeadEyeShape(Group.eyes);
            //            if (CenterOfDeadShapeMove > 0)
            //            {
            //            }

            //        }
            //    }
            //}
        }

        private int getCenterOfDeadShapeMove(List<int> theFields)
        {
            double x = 0;
            double y = 0;
            foreach (int pos in theFields)
            {
                x += getx0(pos);
                y += gety0(pos);
            }
            x /= theFields.Count;
            y /= theFields.Count;
            int thereturn = (int)Math.Round(x) + (int)Math.Round(y) * myboardsize;
            return thereturn;
        }

        private void checkSeki(Group groupfound, bool doneighbors)
        {
            //Test Seki
            foreach (int pos in sekiLibs.Keys.ToList())
            {
                foreach (int nei in Group.getNeighbors(pos, myboardsize).Keys)
                {
                    if (myGroupPosition.ContainsKey(nei))
                    {
                        if (myGroup[myGroupPosition[nei]].myEyes.Count > 1)
                        {
                            sekiLibs.Remove(pos);
                        }
                    }
                }
            }

            if (groupfound.myFields.Count < 3 || groupfound.myEyes.Count > 1 || groupfound.myLibs.Count > 2) return;
            bool isseki = false;
            Group Sekiopp = null;
            List<int> oppgr = new List<int>();
            foreach (int nei in groupfound.myNeighbors.Keys)
            {
                if (myGroupPosition.ContainsKey(nei))
                {
                    Group opp = myGroup[myGroupPosition[nei]];
                    if (!oppgr.Contains(myGroupPosition[nei]))
                    {
                        oppgr.Add(myGroupPosition[nei]);
                    }
                    if (opp.myFields.Count < 3)
                    {
                        isseki = false;
                        break;
                    }
                    if (opp.myLibs.Count > 1 && opp.myLibs.Count == groupfound.myLibs.Count && opp.myEyes.Count < 2)
                    {
                        isseki = true;
                        isseki = issekix(groupfound, opp, isseki) && issekix(opp, groupfound, isseki);
                        if (isseki)
                        {
                            if (opp.myFields.Count < 6 || groupfound.myFields.Count < 6)
                            {
                                if (opp.myEyes.Count == groupfound.myEyes.Count && opp.myEyes.Count == 0)
                                {
                                    if (opp.myFields.Count > 5 && groupfound.myFields.Count > 5)
                                    {
                                        Sekiopp = opp;
                                    }
                                    else
                                    {
                                        isseki = false;
                                        break;
                                    }
                                }
                                else
                                {
                                    isseki = false;
                                    break;
                                }
                            }
                            else
                            {
                                Sekiopp = opp;
                            }
                        }
                    }
                    else
                    {
                        if (opp.myEyes.Count < 2)
                        {
                            isseki = false;
                            break;
                        }
                    }
                }
            }
            if (isseki)
            {
                foreach (int nei in Sekiopp.myNeighbors.Keys)
                {
                    if (myGroupPosition.ContainsKey(nei))
                    {
                        if (myGroupPosition[nei] != groupfound.myposition)
                        {
                            if (myGroup[myGroupPosition[nei]].myEyes.Count < 2)
                            {
                                isseki = false;
                                break;
                            }
                        }
                    }
                }
                foreach (int nei in groupfound.myNeighbors.Keys)
                {
                    if (myGroupPosition.ContainsKey(nei))
                    {
                        if (myGroupPosition[nei] != Sekiopp.myposition)
                        {
                            if (myGroup[myGroupPosition[nei]].myEyes.Count < 2)
                            {
                                isseki = false;
                                break;
                            }
                        }
                    }
                }
                if (isseki)
                {

                    foreach (int lib in Sekiopp.myLibs.Keys)
                    {
                        if (sekiLibs.ContainsKey(lib)) break;
                        if (Sekiopp.myEyes.ContainsKey(lib)) continue;
                        if (groupfound.myEyes.ContainsKey(lib)) continue;
                        sekiLibs[lib] = new List<int>();
                        sekiLibs[lib].Add(groupfound.myposition);
                        sekiLibs[lib].Add(Sekiopp.myposition);
                        if (doneighbors == false)
                        {
                            //++randmovescount;
                        }
                        sekiboard = this.Copy();
                        sekiboard.mymovehistory = new List<int>(mymovehistory);
                        
                    }
                    //writeboardandwait();
                }
            }
            if (doneighbors)
            {
                foreach(int o in oppgr)
                {
                    checkSeki(myGroup[o], false);
                }
            }
        }

        private bool issekix(Group groupfound, Group opp, bool isseki)
        {
            foreach (int lib in opp.myLibs.Keys)
            {
                if (opp.myEyes.ContainsKey(lib)) continue;
                if (!groupfound.myLibs.ContainsKey(lib))
                {
                    isseki = false;
                    break;
                }
                foreach (int nei1 in Group.getNeighbors(lib, myboardsize).Keys)
                {
                    if (!myGroupPosition.ContainsKey(nei1))
                    {
                        if (!opp.myLibs.ContainsKey(nei1))
                        {
                            isseki = false;
                            break;
                        }
                    }
                    else
                    {
                        if (!groupfound.myFields.ContainsKey(nei1) && !opp.myFields.ContainsKey(nei1))
                        {
                            isseki = false;
                            break;
                        }
                    }
                }
            }
            return isseki;
        }

        /// <summary>
        /// checks if the game is allready over 
        /// </summary>

        public void checkwongame(bool bmoves, bool wmoves)
        {
            //return;
            //if (mymovehistory.Count < Math.Sqrt(myboardsize)) return;
            int black = 0;
            int white = 0;
            BAlive.Clear();
            WAlive.Clear();
            foreach (Group cGroup in myGroup.Values)
            {

                if (cGroup.myColor == color.black)
                {
                    if (cGroup.myEyes.Count >= 2)
                    {
                        black = countLivingGroup(black, cGroup, bmoves, wmoves);
                        //if (black == 0) black += (cGroup.getLibertyCount(this) - cGroup.myEyes.Count) / 2;
                        //black += cGroup.myFields.Count;
                        //black += cGroup.myEyes.Count;
                    }
                }
                else
                {
                    if (cGroup.myEyes.Count >= 2)
                    {
                        white = countLivingGroup(white, cGroup, bmoves, wmoves);
                        //if (white == 0) white += (cGroup.getLibertyCount(this) - cGroup.myEyes.Count) / 2;
                        //white += cGroup.myFields.Count;
                        //white += cGroup.myEyes.Count;
                    }
                }

            }

            // count by another mode:
            int bcount = countbyGroups(BAlive, WAlive, wmoves, color.black);
            int wcount = countbyGroups(WAlive, BAlive, bmoves, color.white);
            if
                (bcount != black || wcount != white)
                //(Tree.myRootBoard.mytoMove == color.white)
            {
                if (black >= 45 && bcount < 45 || black < 45 && bcount >= 45 || white >= 37 && wcount < 37 || white < 37 && wcount >= 37)
                {
                    ;
                }
                white = wcount;
                black = bcount;
            }
            //if one cannot move, the result for opponent is even better
            //if (!bmoves && myboardsize * myboardsize + myGame.myKomi - 2 * black > 0)
            //{
            //    myWinner = color.white;
            //}
            //if (!wmoves && myboardsize * myboardsize - myGame.myKomi - 2 * white > 0)
            //{
            //    myWinner = color.black;
            //}
            if (2 * black > myboardsize * myboardsize + myGame.getDynamicKomi())
            {
                myWinner = color.black;
            }
            if (2 * white > myboardsize * myboardsize - myGame.getDynamicKomi())
            {
                myWinner = color.white;
            }
        }

        private int countbyGroups(List<int> Alive, List<int> opAlive, bool moves, color colortocheck)
        {
            List<int> bpoints = new List<int>();
            List<int> blibs = new List<int>();
            foreach (int cGroupnb in myGroup.Keys)
            {

                if (Alive.Contains(cGroupnb) || (!moves && !opAlive.Contains(cGroupnb) && myGroup[cGroupnb].myColor != colortocheck))
                {
                    ;
                }
                else
                {
                    continue;
                }
                Group cGroup = myGroup[cGroupnb];
                foreach (int cpos in cGroup.myEyes.Keys)
                {
                    if (!bpoints.Contains(cpos))
                    {
                        bpoints.Add(cpos);
                    }
                }
                foreach (int cpos in cGroup.myFields.Keys)
                {
                    if (!bpoints.Contains(cpos))
                    {
                        bpoints.Add(cpos);
                    }
                }
                if ((cGroup.myEyes.Count >= 2 || !moves))
                {
                    foreach (int cpos in cGroup.myNeighbors.Keys)
                    {
                        if (!blibs.Contains(cpos) && !cGroup.myEyes.ContainsKey(cpos) && !myGroupPosition.ContainsKey(cpos) && !bpoints.Contains(cpos))
                        {
                            blibs.Add(cpos);
                        }
                    }
                }
            }
            int thereturn = bpoints.Count;
            if (!moves)
            {
                thereturn += blibs.Count;
            }
            else
            {
                thereturn += blibs.Count / 2;
            }
            //            if (isinturn) thereturn += blibs.Count % 2;
            return thereturn;

            //            return bpoints.Count;
        }
        /// <summary>
        /// count points of a living group
        /// </summary>
        /// <param name="count"></param>
        /// <param name="cGroup"></param>
        /// <returns></returns>
        private int countLivingGroup(int count, Group cGroup, bool bmoves, bool wmoves)
        {
            //if (count == 0) count += (cGroup.getLibertyCount(this) - cGroup.myEyes.Count) / 2;
            //count += cGroup.myFields.Count;
            //count += cGroup.myEyes.Count;
            if (cGroup.myColor == color.black)
            {
                if (wmoves == false)
                {
                    count += cGroup.getLibertyCount(this) - cGroup.myEyes.Count;
                }
                else
                {
                    if (count == 0)
                    {
                        count += (cGroup.getLibertyCount(this) - cGroup.myEyes.Count) / 2;
                        if (mytoMove != color.black) ++count;
                    }
                }
                count += cGroup.myFields.Count;
                count += cGroup.myEyes.Count;
                BAlive.Add(cGroup.myposition);
            }
            else
            {
                if (bmoves == false)
                {
                    count += cGroup.getLibertyCount(this) - cGroup.myEyes.Count;
                }
                else
                {
                    if (count == 0)
                    {
                        count += (cGroup.getLibertyCount(this) - cGroup.myEyes.Count) / 2;
                        if (mytoMove != color.white) ++count;
                    }
                }
                count += cGroup.myFields.Count;
                count += cGroup.myEyes.Count;
                WAlive.Add(cGroup.myposition);
            }
            //if (cGroup.myEyes.Count >= 2 || Tree.myRootBoard.mytoMove == color.white)
            //{
                foreach (Group dGroup in myGroup.Values)
                {
                    if (dGroup.myColor != cGroup.myColor) continue;
                    if (dGroup.myEyes.Count >= 2 || BAlive.Contains(dGroup.myposition) || WAlive.Contains(dGroup.myposition)) continue;
                    int connections = 0;
                    int conpos = -1;
                    foreach (int cpos in cGroup.myNeighbors.Keys)
                    {
                        if (dGroup.myNeighbors.ContainsKey(cpos))
                        {
                            if (!myGroupPosition.ContainsKey(cpos))
                            {
                                ++connections;
                                conpos = cpos;
                            }
                        }
                        //foreach (int dpos in dGroup.myNeighbors.Keys)
                        //{
                        //    if (cpos == dpos && !myGroupPosition.ContainsKey(cpos)) ++connections;
                        //}
                    }
                    if (connections > 1)
                    {
                        count = countLivingGroup(count, dGroup, bmoves, wmoves);
                        continue;
                    }
                    if (connections == 1)
                    {
                        int free = 0;
                        foreach (int cNei in Group.getNeighbors(conpos, myboardsize).Keys)
                        {
                            if (!myGroupPosition.ContainsKey(cNei))
                            {
                                ++free;
                            }
                            else
                            {
                                if (myGroup[myGroupPosition[cNei]].myColor != dGroup.myColor)
                                {
                                    free = 2;
                                    break;
                                }
                            }
                        }
                        if (free == 1)
                        {
                            count = countLivingGroup(count, dGroup, bmoves, wmoves);
                            continue;
                        }
                        //}

                    }
                //}
            }
            return count;
        }
        /// <summary>
        /// returns color of the opponent of the given color
        /// </summary>
        /// <param name="thecolor">given color</param>
        /// <returns>color</returns>
        public color getopponent(color thecolor)
        {
            if (thecolor == color.black)
            {
                return color.white;
            }
            return color.black;
        }
        /// <summary>
        /// changes color for next move
        /// </summary>
        internal void changemycolortoMove()
        {
            if (mytoMove == color.black)
            {
                mytoMove = color.white;
                return;
            }
            mytoMove = color.black;
        }
        public Dictionary<int, int> getmoves(color thecolor)
        {
            return getmoves(thecolor, true);
        }
        /// <summary>
        /// produces all possible moves for the given color
        /// </summary>
        /// <param name="thecolor"></param>
        /// <returns>Dictionary<int, int> of possible moves</returns>
        public Dictionary<int, int> getmoves(color thecolor, bool isinitialmove)
        {
            moves.Clear();
            alsoChecked = -1;
            foreach (int pos in myEmptyFields.Keys)
            {
                // only empty fields
                //if (myGroupPosition.ContainsKey(pos))
                //{
                //    ;
                //    continue;
                //}
                // allready checked move
                if (pos == alsoChecked)
                {
                    moves[pos] = pos;
                    continue;
                }
                //if (moves.ContainsKey(pos)) continue;
                bool ismove = checkPositionAsMove(thecolor, pos);
                if (ismove)
                {
                    if (!isinitialmove || checkNoSuperKo(pos))
                    {
                        moves[pos] = pos;
                    }
                }
            }
            return moves;
        }

        private bool checkNoSuperKo(int pos)
        {
            // on first line, extending to two stones, which are atari might lead to superko, so forget the move
            int x = myboardsize / 2 - Math.Abs(pos % myboardsize - (myboardsize / 2));
            int y = myboardsize / 2 - Math.Abs(pos / myboardsize - (myboardsize / 2));
            if (x == 0 || y == 0)
            {
                if (Group.getLibertyCount_full(pos, this, 1) == 1)
                {
                    Group own = null;
                    foreach (int nei in Group.getNeighbors(pos, myboardsize).Keys)
                    {
                        if (myGroupPosition.ContainsKey(nei))
                        {
                            if (myGroup[myGroupPosition[nei]].myColor == mytoMove)
                            {
                                if (own == null)
                                {
                                    own = myGroup[myGroupPosition[nei]];
                                }
                                else
                                {
                                    own = null;
                                    break;
                                }
                            }
                        }
                    }
                    if (own != null && own.myFields.Count == 1)
                    {
                        x = myboardsize / 2 - Math.Abs(own.myposition % myboardsize - (myboardsize / 2));
                        y = myboardsize / 2 - Math.Abs(own.myposition / myboardsize - (myboardsize / 2));
                        if (x == 0 || y == 0)
                        {
                            int thelib = -1;
                            foreach(int t in own.myLibs.Keys)
                            {
                                if (t != pos)
                                {
                                    thelib = t;
                                }
                            }
                            foreach (int nei in Group.getNeighbors(thelib, myboardsize).Keys)
                            {
                                if (!myGroupPosition.ContainsKey(nei)) return true;
                                if (myGroup[myGroupPosition[nei]].myColor != mytoMove) return true;
                            }
                            return false;
                        }

                    }
                }
            }
            
            return true;
        }

        private bool checkPositionAsMove(color thecolor, int pos)
        {
            if (myGroupPosition.ContainsKey(pos)) return false;
            if (sekiLibs.ContainsKey(pos))
            {
            //    //randmovescount++;
                return false;
            }
            bool ismove = false;
            int liberties = 0;
            //if (sekiLibs.ContainsKey(pos)) return false;
            if (pos == alsoChecked) return true;
            foreach (int neighbor in Group.getNeighbors(pos, myboardsize).Keys)
            {
                if (!myGroupPosition.ContainsKey(neighbor))
                {
                    ++liberties;
                    if (neighbor > pos)
                    {
                        alsoChecked = neighbor;
                        //moves[neighbor] = neighbor;
                    }
                    break;
                }
            }
            if (liberties == 0)
            {
                // means here only friendly groups arround with more than 1 lib 
                foreach (int neighbor in Group.getNeighbors(pos, myboardsize).Keys)
                {
                    // is allready checked
                    //if (myGroupPosition.ContainsKey(neighbor))
                    //{
                    Group cGroup = myGroup[myGroupPosition[neighbor]];
                    int libs = cGroup.getLibertyCount(this);
                    if (cGroup.myEyes.ContainsKey(pos))
                    {
                        if (cGroup.myColor == thecolor || cGroup.myEyes.Count > 1 || libs > 1)
                        {
                            ismove = false;
                            liberties = 0;
                            break;
                        }
                    }
                    if (cGroup.myColor == thecolor)
                    {
                        liberties += libs - 1;
                        if (liberties > 0) break;
                    }
                    else
                    {
                        // and fields of opponents groups with only one liberty (except ko)
                        if ((pos != myKoField || cGroup.myFields.Count>1) && libs == 1)
                        {
                            ismove = true;
                            break;
                        }
                    }
                    //}
                }
            }
            if (liberties > 0)
            {
                ismove = true;
                //if (pos > -1 && !myEmptyFields.ContainsKey(pos))
                //{
                //    ++randmovescount;
                //    return false;
                //}
            }
            return ismove;
        }
        /// <summary>
        /// fills Bord as empty board
        /// </summary>
        public void initBoard()
        {
            //for (int i = 0; i < myboardsize * myboardsize; i++)
            //{
            //    myGroups[i] = new Group(i);
            //    myGroups[i].initializeGroup(myboardsize);
            //    myGroups[i].createLiberties(this);
            //}
            mymovehistory.Clear();
            myGroup.Clear();
            myEmptyFields.Clear();
            myGroupPosition.Clear();
            myWinner = color.empty;
            myGame.theRoot = null;
            myKoField = -1;
        }
        /// <summary>
        /// Copies the Board (including Groups and Ko-Position ...)
        /// </summary>
        /// <returns></returns>
        public Board Copy()
        {
            Board theCopy = new Board(myboardsize, myGame);
            theCopy.myGroupPosition = Board.DictCopy2(myGroupPosition);
            theCopy.myGroup = Board.DictCopy(myGroup, this);
            theCopy.sekiLibs = Board.DictCopy3(sekiLibs);
            theCopy.myKoField = myKoField;
            theCopy.mytoMove = mytoMove;
            movesb.Clear();
            movesw.Clear();
            theCopy.fillEmptyFieldsList(myEmptyFields);

            return theCopy;
        }

        /// <summary>
        /// Copies a Dict <int, Group>
        /// </summary>
        /// <param name="theDictToCopy"></param>
        /// <returns></returns>
        static public Dictionary<int, Group> DictCopy(Dictionary<int, Group> theDictToCopy, Board theBoard)
        {
            Dictionary<int, Group> theReturn = new Dictionary<int, Group>();
            foreach (int x in theDictToCopy.Keys.ToArray())
            {
                theReturn[x] = theDictToCopy[x].Copy(theBoard);
            }
            return theReturn;
        }
        static public Dictionary<int, int> DictCopy2(Dictionary<int, int> theDictToCopy)
        {
            Dictionary<int, int> theReturn = new Dictionary<int, int>(theDictToCopy);
            //foreach (int x in theDictToCopy.Keys)
            //{
            //    theReturn[x] = theDictToCopy[x];
            //}
            return theReturn;
        }
        static public Dictionary<int, List<int>> DictCopy3(Dictionary<int, List<int>> theDictToCopy)
        {
            Dictionary<int, List<int>> theReturn = new Dictionary<int, List<int>>();
            foreach (int x in theDictToCopy.Keys)
            {
                theReturn[x] = theDictToCopy[x].ToList();
            }
            return theReturn;
        }
        private void count()
        {
            int anz = 0;
            if (sekiLibs.Count>0)
            {
                ;
            }
            List<int> test = new List<int>();
            foreach (Group cGroup in myGroup.Values.Where(y => y.myColor == color.white))
            {
                anz += cGroup.myFields.Count;
                //anz += cGroup.myEyes.Count;
                foreach (int pos in cGroup.myLibs.Keys)
                {
                    //if (myGroupPosition.ContainsKey(pos)) continue;
                    if (!test.Contains(pos))
                    {
                        test.Add(pos);
                        ++anz;
                    }
                }
                //anz += cGroup.getLibertyCount(this);
            }
            myResult = myboardsize * myboardsize - 2 * anz - myGame.getDynamicKomi() + sekiLibs.Count;

            //int anz2 = 0;
            //List<int> test2 = new List<int>();
            //foreach (Group cGroup in myGroup.Values.Where(y => y.myColor == color.white))
            //{
            //    anz2 += cGroup.myFields.Count;
            //    //anz += cGroup.myEyes.Count;
            //    foreach (int pos in cGroup.myLibs.Keys)
            //    {
            //        //if (myGroupPosition.ContainsKey(pos)) continue;
            //        if (!test2.Contains(pos))
            //        {
            //            test2.Add(pos);
            //            ++anz2;
            //        }
            //    }
            //    //anz += cGroup.getLibertyCount(this);
            //}
            ////double myResult2 = myboardsize * myboardsize - 2 * anz2 - myGame.getDynamicKomi();
            //if (anz != anz2)
            //{
            //    ;
            //}

            //// check if same result for black
            //double theResultB = 0;
            //anz = 0;
            //test.Clear();
            //foreach (Group cGroup in myGroup.Values.Where(y => y.myColor == color.black))
            //{
            //    anz += cGroup.myFields.Count;
            //    foreach (int pos in cGroup.myNeighbors.Keys)
            //    {
            //        if (myGroupPosition.ContainsKey(pos)) continue;
            //        if (!test.Contains(pos))
            //        {
            //            test.Add(pos);
            //            ++anz;
            //        }
            //    } 
            //    //anz += cGroup.myEyes.Count;
            //    //anz += cGroup.getLibertyCount(this);
            //}
            //theResultB = myboardsize * myboardsize - 2 * anz + myGame.myKomi;

            //if (theResultB + myResult != 0)
            //{
            //    writeboard();
            //    writeboard();
            //    ;
            //}

            if (myResult > 0)
            {
                myWinner = color.black;
            }
            else
            {
                if (myResult < 0)
                {
                    myWinner = color.white;
                    myResult = -myResult;
                }
                else
                {
                    myWinner = color.empty;
                }
            }

        }
        private void count(color thecolor)
        {
            int anz = 0;
            List<int> dame = new List<int>();
            List<int> test = new List<int>();
            foreach (Group cGroup in myGroup.Values.Where(y => y.myColor == thecolor))
            {
                if (cGroup.myEyes.Count > 1)
                {
                    anz += cGroup.myFields.Count;

                    foreach (int pos in cGroup.myEyes.Keys)
                    {
                        if (!test.Contains(pos))
                        {
                            test.Add(pos);
                            ++anz;
                        }
                    }
                }
            }

            if (thecolor == color.black)
            {
                myResult = 2 * anz + dame.Count - myGame.getDynamicKomi() - myboardsize * myboardsize;
                if (myResult>0)
                {
                    myWinner = color.black;
                }
                else
                {
                    myWinner = color.empty;
                    myResult = 0;
                }
            }
            else
            {
                myResult = 2 * anz + dame.Count + myGame.getDynamicKomi() - myboardsize * myboardsize;
                if (myResult>0)
                {
                    myWinner = color.white;
                }
                else
                {
                    myWinner = color.empty;
                    myResult = 0;
                }
            }
        }
        private void countnew()
        {
            int anz = 0;
            List<int> dame = new List<int>();
            List<int> test = new List<int>();
            foreach (Group cGroup in myGroup.Values.Where(y => y.myColor == mytoMove))
            {
                anz += cGroup.myFields.Count;

                foreach (int pos in cGroup.myLibs.Keys)
                {
                    if (!test.Contains(pos))
                    {

                        if (cGroup.myEyes.Count > 1)
                        {
                            test.Add(pos);
                            ++anz;
                        }
                        else
                        {
                            bool doadd = true;
                            foreach (int nei in Group.getNeighbors(pos, myboardsize).Keys)
                            {
                                if (myGroupPosition.ContainsKey(nei)
                                    && myGroup[myGroupPosition[nei]].myColor == getopponent(mytoMove))
                                {
                                    doadd = false;
                                    if (!dame.Contains(nei))
                                    {
                                        dame.Add(nei);
                                    }
                                    break;
                                }
                            }
                            if (doadd)
                            {
                                test.Add(pos);
                                ++anz;
                            }
                        }
                    }
                }
            }
            //if (dame.Count > 0)
            //{
            //    ;
            //}
            myResult = myboardsize * myboardsize - dame.Count - 2 * anz - myGame.getDynamicKomi();

            if (myResult > 0)
            {
                myWinner = getopponent(mytoMove);
                double testcount = countnew(mytoMove) - countnew(getopponent(mytoMove));
                if (testcount != 0)
                {
                    ;
                }
                else
                {
                    ;
                }
            }
            else
            {
                if (myResult < 0)
                {
                    myWinner = mytoMove;
                    myResult = -myResult;
                    double testcount = countnew(mytoMove) - countnew(getopponent(mytoMove));
                    if (testcount != 0)
                    {
                        ;
                    }
                    else
                    {
                        ;
                    }

                }
                else
                {
                    myWinner = color.empty;
                }
            }

        }
        private double countnew(color thecolor)
        {
            return countnew(thecolor, true);
        }
        private double countnew(color thecolor, bool countlibs)
        {
            int anz = 0;
            List<int> dame = new List<int>();
            List<int> test = new List<int>();
            foreach (Group cGroup in myGroup.Values.Where(y => y.myColor == thecolor))
            {
                if (countlibs)
                {
                    anz += cGroup.myFields.Count;
                    foreach (int pos in cGroup.myLibs.Keys)
                    {
                        if (!test.Contains(pos))
                        {

                            if (cGroup.myEyes.Count > 1)
                            {
                                test.Add(pos);
                                ++anz;
                            }
                            else
                            {
                                bool doadd = true;
                                foreach (int nei in Group.getNeighbors(pos, myboardsize).Keys)
                                {
                                    if (myGroupPosition.ContainsKey(nei)
                                        && myGroup[myGroupPosition[nei]].myColor == getopponent(thecolor))
                                    {
                                        doadd = false;
                                        if (!dame.Contains(pos))
                                        {
                                            dame.Add(pos);
                                        }
                                        break;
                                    }
                                }
                                if (doadd)
                                {
                                    test.Add(pos);
                                    ++anz;
                                }
                            }
                        }
                    }
                }
                if (cGroup.myEyes.Count > 1)
                {
                    if (!countlibs)
                    {
                        anz += cGroup.myFields.Count;
                    }
                    foreach (int pos in cGroup.myEyes.Keys)
                    {
                        if (!test.Contains(pos))
                        {
                            test.Add(pos);
                            ++anz;
                        }
                    }
                }
            }
            //if (dame.Count > 0)
            //{
            //    ;
            //}
            myResult = myboardsize * myboardsize - dame.Count - 2 * anz;
            if (thecolor == color.white)
            {
                myResult -= myGame.getDynamicKomi();
            }
            else
            {
                myResult += myGame.getDynamicKomi();
            }

            if (myResult > 0 && countlibs)
            {
                myWinner = getopponent(thecolor);
            }
            else
            {
                if (myResult < 0)
                {
                    myWinner = thecolor;
                    myResult = -myResult;
                }
                else
                {
                    myWinner = color.empty;
                    myResult = 0;
                }
            }
            return myResult;
        }
        public int getanyNeutralMove(int themove)
        {
            foreach (Group cGroup in myGroup.Values)
            {
                if (cGroup.alivestat>0.5)
                {
                    foreach (int nei in cGroup.myLibs.Keys)
                    {
                        if (cGroup.myEyes.ContainsKey(nei)) continue;
                        foreach (int nei1 in Group.getNeighbors(nei, myboardsize).Keys)
                        {
                            if (myGroupPosition.ContainsKey(nei1))
                            {
                                if (myGroup[myGroupPosition[nei1]].myColor != cGroup.myColor && myGroup[myGroupPosition[nei1]].alivestat > 0.5)
                                {
                                    if (Group.getLibertyCount_full(nei, this, cGroup.myLibs.Count) >= cGroup.myLibs.Count || cGroup.myEyes.Count>1 )
                                    {
                                        if (checkPositionAsMove(mytoMove, nei))
                                        {
                                            return nei;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return themove;
        }
    
        public int getx(int pos)
        {
            return myboardsize / 2 - Math.Abs(pos % myboardsize - (myboardsize / 2));
        }
        public int gety(int pos)
        {
            return myboardsize / 2 - Math.Abs(pos / myboardsize - (myboardsize / 2));
        }
        public double getdistance(int a, int b)
        {
            return Math.Sqrt((getx0(a) - getx0(b)) * (getx0(a) - getx0(b)) + (gety0(a) - gety0(b)) * (gety0(a) - gety0(b)));
        }
        public int getdistance_int(int a, int b)
        {
            return (getx0(a) - getx0(b)) * (getx0(a) - getx0(b)) + (gety0(a) - gety0(b)) * (gety0(a) - gety0(b));
        }
        public int getx0(int pos)
        {
            return pos % myboardsize;
        }
        public int gety0(int pos)
        {
            return pos / myboardsize;
        }
        public void writeboardandwait()
        {
            writeboard();
            while (Console.ReadKey().ToString() == "") ;
        }
        public void writeboard()
        {
            Dictionary<int, int> black_moves = DictCopy2(getmoves(color.black));
            Dictionary<int, int> white_moves = DictCopy2(getmoves(color.white));

            Console.Write("+");
            for (int i = 0; i < myboardsize; ++i) Console.Write("-");
            if (mymovehistory.Count > 0)
            {
                Console.WriteLine("+ " + mymovehistory.Last().ToString());
            }
            else
            {
                Console.WriteLine();
            }

            string spalte1 = "";
            string spalte2 = "";
            string spalte3 = "";
            string spalte4 = "";
            string spalte5 = "";

            for (int i = 0; i < myboardsize * myboardsize; ++i)
            {
                if (i % myboardsize == 0)
                {
                    spalte1 += "|";
                    spalte2 += "|";
                    spalte3 += "|";
                    spalte4 += "|";
                    spalte5 += "|";

                }
                if (sekiLibs.ContainsKey(i))
                {
                    spalte3 += "s";
                }
                else
                {
                    if (black_moves.ContainsKey(i) && white_moves.ContainsKey(i))
                    {
                        spalte3 += "a";
                    }
                    else
                    {
                        if (black_moves.ContainsKey(i))
                        {
                            spalte3 += "b";

                        }
                        else
                        {
                            if (white_moves.ContainsKey(i))
                            {
                                spalte3 += "w";

                            }
                            else
                            {
                                spalte3 += " ";
                            }

                        }

                    }
                }
                if (!myGroupPosition.ContainsKey(i))
                {
                    spalte1 += " ";
                    spalte2 += " ";
                    spalte4 += " ";
                }
                else
                {
                    string thefield = myGroup[myGroupPosition[i]].myColor.ToString().Substring(0, 1);
                    if (mymovehistory.Count > 0 && i == mymovehistory.Last())
                    {
                        thefield = thefield.ToUpper();
                    }
                    spalte1 += thefield;
                    int l = myGroup[myGroupPosition[i]].getLibertyCount(this);
                    spalte2 += l.ToString().Substring(l.ToString().Length - 1);
                    spalte4 += myGroupPosition[i].ToString().Substring(myGroupPosition[i].ToString().Length - 1);
                }
                bool ispoteye = false;
                bool iseye = false;
                List<int> done = new List<int>();
                foreach (Group cGroup in myGroup.Values)
                {
                    if (cGroup.myEyes.ContainsKey(i) && !done.Contains(i))
                    {
                        spalte5 += "e";
                        iseye = true;
                        done.Add(i);
                    }
                    if (cGroup.mypotEye.ContainsKey(i) && !done.Contains(i))
                    {
                        spalte5 += "p";
                        ispoteye = true;
                        done.Add(i);
                    }

                }
                if (!iseye && !ispoteye) spalte5 += " ";
                if (i % myboardsize == myboardsize - 1)
                {
                    spalte1 += "|";
                    spalte2 += "|";
                    spalte3 += "|";
                    spalte4 += "|";
                    spalte5 += "|";
                    Console.WriteLine(spalte1 + spalte2 + spalte3 + spalte4 + spalte5);
                    spalte1 = "";
                    spalte2 = "";
                    spalte3 = "";
                    spalte4 = "";
                    spalte5 = "";
                }
            }
            Console.Write("+");
            for (int i = 0; i < myboardsize; ++i) Console.Write("-");
            Console.WriteLine("+");

            Console.WriteLine(
                capturesavemovescount.ToString()+" csav "
                + savemovescount.ToString()+" save "
                + hanemovescount.ToString() + " hane "
                + capturemovescount.ToString() + " capt "
                + noselfatarirandmovescount.ToString() + " nosr "
                + randmovescount.ToString() + " rand "
                );
        }
        public BitArray toBitArray()
        {
            BitArray theReturn = new BitArray(myboardsize*myboardsize*2);
            foreach (Group theGroup in myGroup.Values)
            {
                bool theopp = mytoMove != theGroup.myColor;
                if (theopp)
                {
                    foreach (int k in theGroup.myFields.Keys)
                    {
                        theReturn[k + myboardsize * myboardsize] = true;
                    }
                }
                else
                {
                    foreach (int k in theGroup.myFields.Keys)
                    {
                        theReturn[k] = true;
                    }
                }
            }
            return theReturn;
        }
    }
}

